#include "aky_com_include.h"

s_cal_t g_s_cal = {0};
uint8 idata EEPROM_Tab[EEPROM_SIZE]; // Source arm 64byte
uint8_t flash_buf[FLASH_BUF_SIZE];
e_aky_flash_t g_e_flash_err;
s_set_t g_s_set = {0};

uint8 Byte_RDNO(uint16 MEM_ADDR_OFFSET)
{
    uint8 read_ram_data;
    uint8 code *p;
    p = 0 + MEM_ADDR_OFFSET;
    read_ram_data = *p;
    return read_ram_data;
}

void Byte_WtNO(uint16 rom_addr, uint8 rom_data)
{
    // execute Page Erase and Write
    uint16 xdata addbuff;
    addbuff = rom_addr;
    EEPROM_Tab[0] = rom_data;
    PERAM = EEPROM_Tab; // writ source ram address
    rom_addr /= 64;
    rom_addr *= 64;
    PEROMH = rom_addr >> 8; // write target rom address high
    PEROML = rom_addr;      // write target rom address low

    PEBYTE = addbuff % 64;

    PEROML |= 0x0A;

    if (EAL == 0)
    {
        PECMD = 0x1E; // Program command
        _nop_();
        _nop_();
    }
    else
    {
        EAL = 0;
        PECMD = 0x1E;
        _nop_();
        _nop_();
        EAL = 1;
    }
}
void ISPSetRAMAddr(uint8 u8addr)
{
    // set RAM addr
    PERAM = u8addr;
}

void ISPSetROMAddr(uint16 u16addr)
{
    // set ROM addr
    PEROML &= 0x0F;
    // ISP Target Start ROM address Low byte
    PEROML |= ((u16addr & 0x00F0));
    // ISP Target Start ROM address High byte
    PEROMH |= ((u16addr & 0xFF00) >> 8);
    _nop_();
}

void ISPWritePage(void)
{
    // execute Page Erase and Write
    PEROML |= 0x0A;
    if (EAL == 0)
    {
        PECMD = 0x5A;
        _nop_();
        _nop_();
    }
    else
    {
        EAL = 0;
        PECMD = 0x5A;
        _nop_();
        _nop_();
        EAL = 1;
    }
}

void ISPExecute_PAGE(uint16 addr, uint8_t *p_u8_buf)
{
    uint8 idata i = 0;
    for (i = 0; i < EEPROM_SIZE; i++)
    {
        EEPROM_Tab[i] = *p_u8_buf++;
    }

    i = EEPROM_Tab; // get start addr
    ISPSetRAMAddr(i);

    // step 3 : Set ROM start addr (Range is 0x0000~0xFFFF)
    addr /= 64;
    addr *= 64;
    PEROMH = addr >> 8; // write target rom address high
    PEROML = addr;      // write target rom address low
    // step 4 : Progarm one page (64 bytes)
    ISPWritePage();
    // erase all USER ROM
    // ISPEraseAllROM();
}

// 写入多个字节到flash
// addr 写入的开始地址
// p_u8_buf 需要写入的数据buff缓存
// num 写入字节数
// return 错误码  AKY_FLASH_OK  AKY_FLASH_ERR
e_aky_flash_t aky_flash_write_bytes(uint32_t addr, uint8_t *p_u8_buf, uint16_t num)
{
    e_aky_flash_t res = AKY_FLASH_OK;
    uint32_t addr_cnt = 0;
    uint32_t addr_temp = 0;
    uint8_t u8_temp = 0;
    uint16_t u16_temp = 0;

    if ((addr < aky_flash_start_addr || addr > flash_end_addr))
    {
        return AKY_FLASH_ERR; //
    }

    if (addr % 0x02)
    {
        return AKY_FLASH_ERR; // 必须为偶数
    }

    EAL = 0;
    for (addr_cnt = addr; addr_cnt < (addr + num); addr_cnt += 64)
    {
        u8_temp = *p_u8_buf;
        {
            if (addr_cnt >= flash_end_addr)
            {
                break;
            }
            ISPExecute_PAGE(addr_cnt, p_u8_buf);
        }
        p_u8_buf += 64;
    }
    EAL = 1;

    return res;
}

// 默认校压值  经验值
s_cal_t get_default_cal_data(void)
{
    s_cal_t s_cal_res = {0};
    s_cal_res.cal_adc_val = AA1_EXPERIENCE_VALUE;
    s_cal_res.B1 = 3000;
    s_cal_res.cal_cnt = 0;
    
    return s_cal_res;
}

// 从flash读取多个字节到buff
// addr 读取的开始地址
// p_u8_buf 读取的数据buff缓存
// num 读取的字节数
// return 错误码  AKY_FLASH_OK  AKY_FLASH_ERR
e_aky_flash_t aky_flash_read_bytes(uint32_t addr, uint8_t *p_u8_buf, uint16_t num)
{
    e_aky_flash_t res = AKY_FLASH_OK;
    uint32_t addr_cnt = 0;

    if ((addr < aky_flash_start_addr || addr > flash_end_addr))
    {
        return AKY_FLASH_ERR; //
    }
    EAL = 0;

    for (addr_cnt = addr; addr_cnt < (addr + num); addr_cnt++)
    {
        {
            if (addr_cnt >= flash_end_addr)
            {
                break;
            }

            *p_u8_buf++ = Byte_RDNO((addr_cnt & 0xffff));
        }
    }
    EAL = 1;

    return res;
}

// 擦除多个扇区
// addr 擦除的开始地址
//  pages 要擦除的扇区数量
// return 错误码  AKY_FLASH_OK  AKY_FLASH_ERR
e_aky_flash_t aky_flash_erase_pages(uint32_t addr, uint16_t pages)
{
    e_aky_flash_t res = AKY_FLASH_OK;
    uint32_t page_temp = 0;
//    uint16_t i;
		page_temp = pages;
    if ((addr < aky_flash_start_addr || addr > flash_end_addr))
    {
        return AKY_FLASH_ERR; //
    }

    //     addr = addr / AKY_ONE_SEC_SIZE;
    //     addr = addr * AKY_ONE_SEC_SIZE; // 对齐
    //     VIC_Cmd(DISABLE);

    //     for (i = 0; i < pages; i++)
    //     {
    //         {
    //             if ((addr + (i * AKY_ONE_SEC_SIZE)) >= flash_end_addr)
    //             {
    //                 break;
    //             }
    // #if (AKY_FLASH_DEBUG_ENABLE == 1)
    //             bank_last = PAGESEL;
    //             FLASH_BANKSel(BANK1); // FLASH BANK分页选择(BANK不同，程序中对flash地址0x8000~0xFFFF操作时，实际操作地址不同)
    //             status = FLASH_ErasePage((addr + (i * AKY_ONE_SEC_SIZE)));
    //             FLASH_BANKSel(bank_last); // FLASH BANK分页选择(BANK不同，程序中对flash地址0x8000~0xFFFF操作时，实际操作地址不同)
    // #else
    //             bank_last = PAGESEL;
    //             FLASH_BANKSel(BANK3); // FLASH BANK分页选择(BANK不同，程序中对flash地址0x8000~0xFFFF操作时，实际操作地址不同)
    //             status = FLASH_ErasePage((addr + (i * AKY_ONE_SEC_SIZE)));
    //             FLASH_BANKSel(bank_last); // FLASH BANK分页选择(BANK不同，程序中对flash地址0x8000~0xFFFF操作时，实际操作地址不同)
    // #endif

    //         }

    //         if (status != FLASH_COMPLETE)
    //         {
    //             res = AKY_FLASH_ERR;
    //             break;
    //         }
    //         else
    //         {
    //             res = AKY_FLASH_OK;
    //         }
    //     }
    //     VIC_Cmd(ENABLE);

    return res;
}


// 得出多个字节的校验和
// p_u8_buf 要进行计算的缓存
// num 字节数
// return 校验和
uint8_t get_bytes_checksum(uint8_t *p_u8_buf, uint16_t num)
{
    uint16_t i = 0;
    uint8_t res = 0;

    for (i = 0; i < num; i++)
    {
        res += *p_u8_buf++;
    }

    return res;
}

// 得出结构体到checksum中间字节数
// p_start_addr 结构体开始地址
// p_stop_addr 结构体checksum的地址
// return 字节数
uint16_t get_stru_checksum_offset_bytes(uint8_t *p_start_addr, uint8_t *p_stop_addr)
{
    uint16_t res = 0;
    res = p_stop_addr - p_start_addr;
    return res;
}

// 保存校压
void flash_save_cal_data(s_cal_t s_cal)
{
    uint16_t bytes = 0;
    uint16_t i;
    uint8_t *p_u8_buf;
    uint8_t *p_u8_buf_const;
    s_cal.cal_cnt++;
    
    bytes = get_stru_checksum_offset_bytes((uint8_t *)&s_cal, (uint8_t *)&s_cal.check_sum);
    s_cal.check_sum = get_bytes_checksum((uint8_t *)&s_cal, bytes);

    memset((uint8_t *)flash_buf, 0xff, FLASH_BUF_SIZE);
    p_u8_buf = (uint8_t *)&s_cal;
    p_u8_buf_const = (uint8_t *)&s_cal;
    for (i = 0; i < sizeof(s_cal_t) * CAL_DATA_MAX_SAVE_CNT; i++) // 保存次
    {
        flash_buf[i] = *p_u8_buf++;
        if (p_u8_buf >= p_u8_buf_const + sizeof(s_cal_t))
        {
            p_u8_buf = (uint8_t *)&s_cal;
        }
    }

    aky_flash_erase_pages(cal_addr, 1);
    aky_flash_write_bytes(cal_addr, (uint8_t *)flash_buf, AKY_ONE_SEC_SIZE);
    aky_flash_erase_pages(cal_back_addr, 1);
    aky_flash_write_bytes(cal_back_addr, (uint8_t *)flash_buf, AKY_ONE_SEC_SIZE);
}

// 取flash的校压值数据
s_cal_t flash_get_cal_data(void)
{
    s_cal_t s_cal_res = {0};
    uint16_t bytes = 0;
    uint16_t i, j = 0;
    uint16_t ok_mask = 0;
    bytes = get_stru_checksum_offset_bytes((uint8_t *)&s_cal_res, (uint8_t *)&s_cal_res.check_sum);

    ok_mask = 0;
    for (i = 0; i < CAL_DATA_MAX_SAVE_CNT; i++)
    {
        g_e_flash_err = aky_flash_read_bytes(cal_addr + (i * sizeof(s_cal_t)), (uint8_t *)&s_cal_res, sizeof(s_cal_t));
        if (s_cal_res.check_sum == get_bytes_checksum((uint8_t *)&s_cal_res, bytes) && g_e_flash_err == AKY_FLASH_OK) // 校验通过
        {
            ok_mask |= (0x01 << i);
        }
    }
    if (ok_mask > 0)
    {
        for (i = 0; i < CAL_DATA_MAX_SAVE_CNT; i++)
        {
            if ((ok_mask & (0x01 << i)) != (0x01 << i)) // 如果有错误
            {
                for (j = 0; j < CAL_DATA_MAX_SAVE_CNT; j++)
                {
                    if ((ok_mask & (0x01 << j)) == (0x01 << j)) // 查到正确的则重新写回主地址
                    {
                        g_e_flash_err = aky_flash_read_bytes(cal_addr + (j * sizeof(s_cal_t)), (uint8_t *)&s_cal_res, sizeof(s_cal_t));
                        if (s_cal_res.check_sum == get_bytes_checksum((uint8_t *)&s_cal_res, bytes) && g_e_flash_err == AKY_FLASH_OK) // 校验通过
                        {
                            flash_save_cal_data(s_cal_res); // 写回主地址
                            goto get_cal_data_exit;
                        }
                    }
                }
            }
        }
    }

    if (s_cal_res.check_sum != get_bytes_checksum((uint8_t *)&s_cal_res, bytes) || g_e_flash_err == AKY_FLASH_ERR) // 校验出错
    {
        for (i = 0; i < CAL_DATA_MAX_SAVE_CNT; i++)
        {
            g_e_flash_err = aky_flash_read_bytes(cal_back_addr + (i * sizeof(s_cal_t)), (uint8_t *)&s_cal_res, sizeof(s_cal_t));
            if (s_cal_res.check_sum == get_bytes_checksum((uint8_t *)&s_cal_res, bytes) && g_e_flash_err == AKY_FLASH_OK) // 校验通过
            {
                break;
            }
        }

        if (s_cal_res.check_sum != get_bytes_checksum((uint8_t *)&s_cal_res, bytes) || g_e_flash_err == AKY_FLASH_ERR) // 校验出错
        {
            s_cal_res = get_default_cal_data(); // 读默认
        }
        else
        {
            flash_save_cal_data(s_cal_res); // 备份写回主地址
        }
    }
    else
    {
    }
get_cal_data_exit:
    return s_cal_res;
}

// 默认设定值
s_set_t get_default_set_data(void)
{
    s_set_t s_set_res = {0};

    s_set_res.inflat_limit_pres_val = 280; // 
    s_set_res.inflat_time = 10; // 
    s_set_res.deflat_time = 2; // 
    s_set_res.last_selec_menu_index = 0; // 

    s_set_res.fill_byte1 = 0x5a; // 填充字节
    s_set_res.fill_byte2 = 0x5a;
    s_set_res.fill_byte3 = 0x5a;

    return s_set_res;
}

// 保存设定值到flash
void store_set_to_flash(s_set_t s_set)
{
    uint16_t bytes = 0;
    uint16_t i;
    uint8_t *p_u8_buf;
    uint8_t *p_u8_buf_const;
    bytes = get_stru_checksum_offset_bytes((uint8_t *)&s_set, (uint8_t *)&s_set.check_sum);
    s_set.check_sum = get_bytes_checksum((uint8_t *)&s_set, bytes);

    memset((uint8_t *)flash_buf, 0xff, FLASH_BUF_SIZE);
    p_u8_buf = (uint8_t *)&s_set;
    p_u8_buf_const = (uint8_t *)&s_set;
    for (i = 0; i < sizeof(s_set_t) * SET_DATA_MAX_SAVE_CNT; i++) // 保存次
    {
        flash_buf[i] = *p_u8_buf++;
        if (p_u8_buf >= p_u8_buf_const + sizeof(s_set_t))
        {
            p_u8_buf = (uint8_t *)&s_set;
        }
    }

    aky_flash_erase_pages(user_set_addr, 1);
    aky_flash_write_bytes(user_set_addr, (uint8_t *)flash_buf, AKY_ONE_SEC_SIZE);
    aky_flash_erase_pages(user_set_back_addr, 1);
    aky_flash_write_bytes(user_set_back_addr, (uint8_t *)flash_buf, AKY_ONE_SEC_SIZE);
}

// 从flash取设定值
s_set_t get_flash_set_data(void)
{
    s_set_t s_set_res = {0};
    uint16_t bytes = 0;
    uint16_t i, j = 0;
    uint16_t ok_mask = 0;

    bytes = get_stru_checksum_offset_bytes((uint8_t *)&s_set_res, (uint8_t *)&s_set_res.check_sum);

    ok_mask = 0;
    for (i = 0; i < SET_DATA_MAX_SAVE_CNT; i++)
    {
        g_e_flash_err = aky_flash_read_bytes(user_set_addr + (i * sizeof(s_set_t)), (uint8_t *)&s_set_res, sizeof(s_set_t));
        if (s_set_res.check_sum == get_bytes_checksum((uint8_t *)&s_set_res, bytes) && g_e_flash_err == AKY_FLASH_OK) // 校验通过
        {
            ok_mask |= (0x01 << i);
        }
    }
    if (ok_mask > 0)
    {
        for (i = 0; i < SET_DATA_MAX_SAVE_CNT; i++)
        {
            if ((ok_mask & (0x01 << i)) != (0x01 << i)) // 如果有错误
            {
                for (j = 0; j < SET_DATA_MAX_SAVE_CNT; j++)
                {
                    if ((ok_mask & (0x01 << j)) == (0x01 << j)) // 查到正确的则重新写回主地址
                    {
                        g_e_flash_err = aky_flash_read_bytes(user_set_addr + (j * sizeof(s_set_t)), (uint8_t *)&s_set_res, sizeof(s_set_t));
                        if (s_set_res.check_sum == get_bytes_checksum((uint8_t *)&s_set_res, bytes) && g_e_flash_err == AKY_FLASH_OK) // 校验通过
                        {
                            store_set_to_flash(s_set_res); // 写回主地址
                            goto get_set_data_exit;
                        }
                    }
                }
            }
        }
    }

    if (s_set_res.check_sum != get_bytes_checksum((uint8_t *)&s_set_res, bytes) || g_e_flash_err == AKY_FLASH_ERR) // 校验出错
    {
        for (i = 0; i < SET_DATA_MAX_SAVE_CNT; i++)
        {
            g_e_flash_err = aky_flash_read_bytes(user_set_back_addr + (i * sizeof(s_set_t)), (uint8_t *)&s_set_res, sizeof(s_set_t));
            if (s_set_res.check_sum == get_bytes_checksum((uint8_t *)&s_set_res, bytes) && g_e_flash_err == AKY_FLASH_OK) // 校验通过
            {
                break;
            }
        }

        if (s_set_res.check_sum != get_bytes_checksum((uint8_t *)&s_set_res, bytes) || g_e_flash_err == AKY_FLASH_ERR) // 校验出错
        {
            s_set_res = get_default_set_data(); // 读默认
        }
        else
        {
            store_set_to_flash(s_set_res); // 备份写回主地址
        }
    }
    else
    {
    }
get_set_data_exit:
    return s_set_res;
}
